/**
 * Copyright (c) 2022 Beijing Jiaotong University
 * PhotLab is licensed under [Open Source License].
 * You can use this software according to the terms and conditions of the [Open Source License].
 * You may obtain a copy of [Open Source License] at: [https://open.source.license/]
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *
 * See the [Open Source License] for more details.
 *
 * Author: Zhenjie Wei
 * Created: Aug. 10, 2023
 * Supported by: National Key Research and Development Program of China
 */

import { Disposable } from "@/common/disposable"
import { PhotGrid, PhotDetector, PhotMaterial, PhotSource, PhotWaveguide, PhotMaterialProperty } from "@/common/types/phot_types"
import { deviceService as deviceAPI } from "./client"
import { uid_rt } from "@/common/types/base_types"
import { deepClone } from "@/utils"

export const deviceManager = new class DeviceManager extends Disposable {
    private _currentPhotGrid: any | null = null
    private _photGrids: Map<string | number | any, any> = new Map()
    private _photGridHistorys: Map<string | number, any> = new Map()
    private _currentPhotGridId: number | null | any = null
    private _materials: PhotMaterial[] = []
    private _lightSourceList: any = []
    private _waveSourceList: any = []
    private _detectorSourceList: any = []
    private _figures: Map<number, any> = new Map()
    private _taskStatus: Map<number, any> = new Map()
    private _xFigure: any = {}
    private _yFigure: any = {}
    private _zFigure: any = {}
    private _compoParametersList: Map<number, any> = new Map()

    constructor() {
        super()
        return
    }

    public get TASK_STATUS(): any {
        return {
            START: 1,
            RUNNING: 2,
            CLOSED: 3
        }
    }

    public get taskStatus(): any {
        return this._taskStatus
    }

    public get materials(): PhotMaterial[] {
        return this._materials
    }

    public get photGrid(): any | null {
        return this._currentPhotGrid
    }

    public get photGrids(): any | null {
        return this._photGrids
    }

    public get photGridHistorys(): any | null {
        return this._photGridHistorys
    }

    public get photGridId(): any | null {
        return this._currentPhotGridId
    }

    public get lightSourceList(): any[] {
        return this._lightSourceList
    }
    public get waveSourceList(): any[] {
        return this._waveSourceList
    }
    public get detectorSourceList(): any[] {
        return this._detectorSourceList
    }
    public get figures(): any {
        return this._figures
    }
    public get xFigure(): any {
        return this._xFigure
    }
    public get yFigure(): any {
        return this._yFigure
    }
    public get zFigure(): any {
        return this._zFigure
    }
    public get compoParametersList(): any {
        return this._compoParametersList
    }

    public async addGrid(grid: PhotGrid = new PhotGrid()) {  // 添加仿真网络
        console.group('deviceManager.addGrid')
        const gridId = uid_rt()
        grid.gridId = gridId
        await deviceAPI.addGrid(grid)
        this._currentPhotGrid = grid
        this._currentPhotGridId = gridId
        this._photGrids.set(gridId, grid)
        this._compoParametersList.set(gridId, {
            light: new Array,
            waveguide: new Array,
            detector: new Array
        })
        const figures = await this.getFigures()
        this._figures.set(gridId, figures)
        console.log('grid:', this._currentPhotGrid)
        console.log('gridid:', this._currentPhotGridId)
        console.groupEnd()
    }
    public async getGrid(gridId: number) {
        await deviceAPI.getGrid(gridId)
    }
    public async switchGrid(gridId: number) {
        const grid = this._photGrids.get(gridId)
        this._currentPhotGrid = grid
        this._currentPhotGridId = gridId
    }
    public async openGrid(gridPath: string) {
        const photGrid: any = await deviceAPI.openGrid(gridPath)
        if (!photGrid) {
            return Promise.reject("gridManager.openGrid failed. grid not found.")
        }
        this._currentPhotGrid = photGrid
        this._currentPhotGridId = photGrid.gridId
        this._photGrids.set(photGrid.gridId, photGrid)
        const figures = await this.getFigures()
        this._figures.set(photGrid.gridId, figures)
        this._compoParametersList.set(this._currentPhotGridId!, {
            light: new Array,
            waveguide: new Array,
            detector: new Array
        })
    }
    public async closeGrid(gridId?: number | null) {
        console.group("graphManager.closeGrid")
        if (!gridId) {
            gridId = this._currentPhotGridId
        }
        if (!gridId) {
            return Promise.reject("gridManager.closeGrid failed. grid id not found.")
        }

        await deviceAPI.closeGrid(gridId)
        this._photGrids.delete(gridId)
        this._currentPhotGridId = null
        this._currentPhotGrid = null
        this._xFigure = null
        this._yFigure = null
        this._zFigure = null
        this._figures.delete(gridId)
        this._compoParametersList.delete(gridId)
        console.groupEnd()
    }
    public async saveGrid(gridId?: number | null) {
        console.log("gridManager.saveGrid")
        if (!gridId) {
            gridId = this._currentPhotGridId
        }
        if (!gridId) {
            return Promise.reject("gridManager.saveGrid failed. grid id not found.")
        }
        await deviceAPI.saveGrid(gridId)
        this._taskStatus.set(gridId, this.TASK_STATUS.START)
    }

    public async saveGridAs(path: string) {
        console.group("gridManager.saveGridAs ", path)
        if (!this._currentPhotGridId) {
            return Promise.reject("gridManager.saveGridAs failed. grid id not found.")
        }
        console.log(this._currentPhotGridId, path)
        await deviceAPI.saveGridAs(this._currentPhotGridId, path)
        console.groupEnd()
    }
    public async updateGrid(grid: PhotGrid = new PhotGrid()) {
        await deviceAPI.updateGrid(grid)
    }
    public async deleteGrid(gridId: number) {
        await deviceAPI.deleteGrid(gridId)
    }
    public async addDetector(detector: PhotDetector = new PhotDetector()) {   // 添加探测器
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        const detectorId = uid_rt()
        detector.detectorId = detectorId
        await deviceAPI.addDetector(this._currentPhotGridId!, detector)
    }
    public async getDetector(detectorId: number) {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        return await deviceAPI.getDetector(this._currentPhotGridId!, detectorId)
    }
    public async updateDetector(detector: PhotDetector) {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        await deviceAPI.updateDetector(this._currentPhotGridId!, detector)
    }
    public async deleteDetector(detectorId: number) {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        await deviceAPI.deleteDetector(this._currentPhotGridId!, detectorId)
    }
    public async addMaterial(material: PhotMaterial = new PhotMaterial()) {  // 添加材料
        await deviceAPI.addMaterial(material)
    }
    public async getMaterial(materialName: string) {
        await deviceAPI.getMaterial(materialName)
    }
    public async updateMaterial(materialName: string, material: PhotMaterial = new PhotMaterial()) {
        await deviceAPI.updateMaterial(materialName, material)
    }
    public async updateMaterialProperty(materialName: string, propertyId: any, property: PhotMaterialProperty = new PhotMaterialProperty()) {
        await deviceAPI.updateMaterialProperty(materialName, propertyId, property)
    }
    public async deleteMaterial(materialName: string) {
        await deviceAPI.deleteMaterial(materialName)
    }
    public async deleteMaterialProperty(materialName: string, propertyId: number) {
        await deviceAPI.deleteMaterialProperty(materialName, propertyId)
    }
    public async getMaterials() {
        console.group('deviceManager.getMaterials')
        this._materials = await deviceAPI.getMaterials() || []
        console.groupEnd()
        return this._materials
    }
    public async getWaveguideDefaultParameterList(name: string) {
        console.group('deviceManager.getWaveguideDefaultParameterList')
        const parameters: any = await deviceAPI.getWaveguideDefaultParameterList(name) || ''
        console.groupEnd()
        return parameters
    }
    public async getAllWaveguideDefaultParameterList(name: string) {
        console.group('deviceManager.getAllWaveguideDefaultParameterList')
        const parameters: any = await deviceAPI.getAllWaveguideDefaultParameterList() || ''
        console.groupEnd()
        return parameters
    }
    public async addSource(source: PhotSource = new PhotSource()) { // 添加光源
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        const sourceId = uid_rt()
        source.sourceId = sourceId
        await deviceAPI.addSource(this._currentPhotGridId!, source)
    }
    public async getSource(sourceId: number) {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        return await deviceAPI.getSource(this._currentPhotGridId!, sourceId)
    }
    public async updateSource(source: PhotSource) {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        await deviceAPI.updateSource(this._currentPhotGridId!, source)
    }
    public async deleteSource(sourceId: number) {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        await deviceAPI.deleteSource(this._currentPhotGridId!, sourceId)
    }
    public async addWaveguide(waveguide: PhotWaveguide = new PhotWaveguide()) {    // 添加波导
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        const waveguideId = uid_rt()
        waveguide.waveguideId = waveguideId
        waveguide.parameters = JSON.stringify(waveguide)
        await deviceAPI.addWaveguide(this._currentPhotGridId!, waveguide)
    }
    public async getWaveguide(waveguideId: number) {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        return await deviceAPI.getWaveguide(this._currentPhotGridId!, waveguideId)
    }
    public async updateWaveguide(waveguide: PhotWaveguide) {
        console.log(waveguide)
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        const res = await deviceAPI.updateWaveguide(this._currentPhotGridId!, waveguide)
        console.log(res)
    }
    public async deleteWaveguide(waveguideId: number) {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        await deviceAPI.deleteWaveguide(this._currentPhotGridId!, waveguideId)
    }
    public async run() {   // 计算仿真网络
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        await deviceAPI.run(this._currentPhotGridId!)
        this._taskStatus.set(this._currentPhotGrid, this.TASK_STATUS.RUNNING)
    }
    public async getFigures(axisIndex: number[] = [0,0,0]) {    // 获取视图
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        const sectional = await deviceAPI.getFigures(this._currentPhotGridId!, axisIndex, 'Sectional View')
        const refractiveIndex = await deviceAPI.getFigures(this._currentPhotGridId!, axisIndex, 'Refractive Index View')
        const field = await deviceAPI.getFigures(this._currentPhotGridId!, axisIndex, 'Field View')
        const figures = {...sectional, ...refractiveIndex, ...field}
        return figures
    }
    public async getFigure(axis: string, axisIndex: number = 0, fileType: string = 'Sectional View') {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        const figure = await deviceAPI.getFigure(this._currentPhotGridId!, axis, axisIndex, fileType)
        // this._figures.set(axis, figure)
        if (axis === 'x') {
            this._xFigure = figure
        }
        if (axis === 'y') {
            this._yFigure = figure
        }
        if (axis === 'z') {
            this._zFigure = figure
        }
        return figure
    }
    public async saveFigureAs(axis: string, axisIndex: number = 0, filePath: string, fileType: string = 'Sectional View') {
        if (!this._currentPhotGrid) {
            return Promise.reject('Current PhotGrid not found.')
        }
        console.log(this._currentPhotGridId, axis, filePath)
        await deviceAPI.saveFigureAs(this._currentPhotGridId!, axis, axisIndex, filePath, fileType)
    }

    public setSource(obj: any, type: any) {
        console.group('deviceManager.addSource')
        if (!this._currentPhotGrid || !this._currentPhotGridId) {
            return false
        }
        if (type === 'light') {
            if (this._lightSourceList.filter((item: any) => item.type === obj.type).length > 0) {
                return console.log('已存在光源列表')
            }
            this._lightSourceList.push(obj)
        }
        if (type === 'wave') {
            if (this._waveSourceList.filter((item: any) => item.type === obj.type).length > 0) {
                return console.log('已存在波导列表')
            }
            this._waveSourceList.push(obj)
        }
        if (type === 'detector') {
            if (this._detectorSourceList.filter((item: any) => item.type === obj.type).length > 0) {
                return console.log('已存在监视器列表')
            }
            this._detectorSourceList.push(obj)
        }
        console.groupEnd()
    }

    public addSourceItem(obj: any, idx: any, type: any = 'light') {
        console.group('deviceManager.addSourceItem')
        if (!this._currentPhotGrid || !this._currentPhotGridId) {
            return false
        }
        if (type === 'light') {
            this._lightSourceList[idx].list.push(obj)
            const source = new PhotSource()
            source.sourceType = this._lightSourceList[idx].type
            this.addSource(source)
        }
        if (type === 'wave') {
            this._waveSourceList[idx].list.push(obj)
            this.addWaveguide()
        }
        if (type === 'detector') {
            this._detectorSourceList[idx].list.push(obj)
            this.addDetector()
        }
        console.log(type + ':', obj)
        console.groupEnd()
    }



    public activate() {
        return
    }
}